<!--
 * @Author: aster lipian1004@163.com
 * @Date: 2025-02-20 17:11:39
 * @FilePath: \aster-flowable-uniapp\src\components\form\render\summary-formula.vue
 * @Description: 汇总计算
 * Copyright (c) 2025 by Aster, All Rights Reserved.
-->
<template>
  <van-field
    v-if="!_hidden"
    v-model="_value"
    :name="formItemProp"
    :rules="_rules"
    :required="_required"
    :readonly="_readonly"
    :input-align="FieldInputAlignEnum.RIGHT"
    :error-message-align="FieldInputAlignEnum.RIGHT"
    :label-width="showLabel ? '' : '8rpx'"
    clearable
    type="number"
  >
    <template #label>
      <text v-if="showLabel">{{ formItem.title }}</text>
    </template>
  </van-field>
</template>
<script setup lang="ts">
  import { evaluateFormula } from '@/utils/workflow';
  import { computed, PropType, watch } from 'vue';
  import { isNotEmpty } from '@/utils/is';
  import { FormPermissionEnum } from '@/enums/workFlowEnum';
  import { FieldInputAlignEnum } from '@/enums/formEnum';
  import { formatNumber } from '@/utils/digit';
  import { Toast } from '@/utils/uniapi/prompt';

  const emit = defineEmits(['update:value']);
  const props = defineProps({
    value: {
      type: Number,
      default: '',
    },
    mode: {
      type: String as PropType<'design' | 'form' | 'search' | 'table' | 'print'>,
      default: 'design',
    },
    formData: {
      type: Object as PropType<WorkForm.FormDataModel>,
      default: {},
    },
    formItem: {
      type: Object as PropType<WorkComponent.ComponentConfig>,
      default: {},
    },
    tableId: {
      type: String,
      default: '',
    },
    tableIndex: {
      type: Number,
      default: 0,
    },
    showLabel: {
      type: Boolean,
      default: true,
    },
  });

  // 键
  const formItemProp = computed(() => {
    if (isNotEmpty(props.tableId)) {
      return props.tableId + '.' + props.tableIndex + '.' + props.formItem.id;
    } else {
      return props.formItem.id;
    }
  });

  /**
   * 计算公式的值
   */
  const parseFormula = () => {
    if (props.formItem.props.formula) {
      let expression = props.formItem.props.formula;
      console.log('------当前公式：', expression);
      let regex = /\[\?\]/g; // 正则表达式，全局匹配 `[?]`
      if (regex.test(expression)) {
        // 通过正则获取函数名称和函数参数
        let regex = /([\w]+)\(([^)]+)\)/;
        let match = regex.exec(expression);
        if (match) {
          handleFunction(match);
        } else {
          // 说明没使用函数，并且计算公式在当前明细表中，所以让支持一般的表达式解析，
          if (isNotEmpty(props.tableId)) {
            expression = expression.replaceAll('?', props.tableIndex);
          }
          _value.value = evaluateFormula(expression, props.formData);
        }
      } else {
        //如果没有明细表变量，则走正常的表达式处理
        _value.value = evaluateFormula(expression, props.formData);
      }
    }
  };

  /**
   * 处理函数
   * @param match
   *        match[0]:"AVG(field6867564635973[?].field1124964639172 )"
   *        match[1]:"AVG"
   *        match[2]:"field6867564635973[?].field1124964639172 "
   */
  const handleFunction = (match: any[]) => {
    let functionName = match[1];
    let functionArgs = match[2];
    if (functionArgs.indexOf('[?]') > -1) {
      // 获取明细表中的数组名称，即fieldxxxx开头的数组
      let fields = functionArgs.split('[?].');
      let fieldArray = [];
      if (fields.length > 0) {
        let array = fields[0];
        fieldArray = props.formData?.[array] ? props.formData[array] : [];
      }

      switch (functionName.toUpperCase()) {
        case 'SUM':
          _value.value = sumFunction(fieldArray);
          break;
        case 'AVG':
          _value.value = sumFunction(fieldArray) / (fieldArray.length > 0 ? fieldArray.length : 1);
          break;
        case 'MAX':
          _value.value = maxFunction(fieldArray);
          break;
        case 'MIN':
          _value.value = minFunction(fieldArray);
          break;
        default:
          Toast('明细表中暂不支持该函数：' + functionName);
          break;
      }
    }
  };

  /**
   * @description: 求和函数
   * @param fieldArray：明细表的字段数组
   */
  const sumFunction = (fieldArray: any[]) => {
    let sum = 0;
    let expression = props.formItem.props.formula;
    fieldArray.forEach((_item, index) => {
      // 通过循环依次替换表达式中的下标，然后计算表达式的值
      const subExp = expression.replace(/\[\?\]/g, () => '[' + index + ']');
      sum += evaluateFormula(subExp, props.formData);
    });
    return sum;
  };

  /**
   * @description: 最大值函数
   * @param fieldArray
   */
  function maxFunction(fieldArray: any[]) {
    let expression = props.formItem.props.formula;
    let max = 0;
    fieldArray.forEach((_item, index) => {
      // 通过循环依次替换表达式中的下标，然后计算表达式的值
      const subExp = expression.replace(/\[\?\]/g, () => '[' + index + ']');
      const currentMax = evaluateFormula(subExp, props.formData);
      if (index === 0) {
        max = currentMax;
      }
      if (currentMax > max) {
        max = currentMax;
      }
    });
    return max;
  }
  /**
   * @description: 最小值函数
   * @param fieldArray
   */
  function minFunction(fieldArray: any[]) {
    let expression = props.formItem.props.formula;
    let min = 0;
    fieldArray.forEach((_item, index) => {
      // 通过循环依次替换表达式中的下标，然后计算表达式的值
      const subExp = expression.replace(/\[\?\]/g, () => '[' + index + ']');
      const currentMax = evaluateFormula(subExp, props.formData);
      if (index === 0) {
        min = currentMax;
      }
      if (currentMax < min) {
        min = currentMax;
      }
    });
    return min;
  }

  /**
   * @description: 组件值
   */
  const _value = computed({
    get() {
      return props.value;
    },
    set(val) {
      emit('update:value', formatNumber(val, props.formItem.props.precision));
    },
  });

  /**
   * @description: 是否必填, true-必填
   */
  const _required = computed(() => {
    return props.formItem.props.required;
  });

  /**
   * @description: 是否只读, true-只读
   */
  const _readonly = computed(() => {
    let r = props.formItem.props.readonly;
    if (props.formItem.operation && props.formItem.operation.length > 0) {
      r = r || props.formItem.operation[0] == FormPermissionEnum.READONLY;
    }
    return r;
  });

  /**
   * @description: 校验规则
   */
  const _rules = computed(() => {
    const isRequired = _required.value;
    if (props.mode != 'form') {
      return [];
    }
    return isRequired ? [{ required: true, message: `请输入${props.formItem.title}` }] : [];
  });

  watch(
    () => props.formData,
    () => {
      parseFormula();
    },
    { immediate: true, deep: true },
  );

  /**
   * @description: 是否隐藏, true-隐藏
   */
  const _hidden = computed(() => {
    let r = false;
    // 解析隐藏条件公式
    if (props.formItem.props.hidden) {
      let expression = props.formItem.props.hidden;
      // 如果是子表中的控件，则需要用到下标
      if (isNotEmpty(props.tableId)) {
        expression = expression.replaceAll('?', props.tableIndex);
      }
      r = evaluateFormula(expression, props.formData);
    }
    // 判断流程节点下该控件是否隐藏
    if (props.formItem.operation && props.formItem.operation.length > 0) {
      r = r || props.formItem.operation[0] == FormPermissionEnum.HIDDEN;
    }
    return r;
  });

  defineExpose({
    _hidden,
  });
</script>
<style scoped lang="scss"></style>
